package com.atguigu.gulimall.search.thread;

import java.util.concurrent.*;

/**
 * @Author : Jungle
 * @Description :
 */
public class ThreadTest {
    public static ExecutorService executor = Executors.newFixedThreadPool(10);

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.printf("CompletableFuture==>%3s \n", "main...start");
        //CompletableFuture.runAsync(()->{
        //    System.out.printf("当前线程==>%3s \n", Thread.currentThread().getName());
        //    int i = 10 / 2;
        //    System.out.printf("运行结果==>%3d \n", i);
        //},executor);
        /**
         * 1、方法完成后的感知
         */
        //CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        //    System.out.printf("当前线程==>%3s \n", Thread.currentThread().getName());
        //    int i = 10 / 0;
        //    System.out.printf("运行结果==>%3d \n", i);
        //    return i;
        //}, executor)
        //        //whenComplete 虽然能得到异常信息，但是没法修改返回数据
        //        .whenComplete((res, exception) -> {
        //            System.out.printf("whenComplete---异步任务完成了 结果是==>%3s  异常是==>%3s \n", res, exception);
        //        })
        //        //可以感知异常，同时返回默认值
        //        .exceptionally(throwable -> {
        //            //这里自定义设置返回10
        //            return 10;
        //        });

        /**
         * 2、方法执行完成后的处理
         */
        //CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
        //    System.out.printf("当前线程==>%3s \n", Thread.currentThread().getName());
        //    int i = 10 / 4;
        //    System.out.printf("运行结果==>%3d \n", i);
        //    return i;
        //}, executor)
        //        // R apply(T t, U u);   res,thr 结果，异常
        //        .handle((res,thr)->{
        //            if (res != null) {
        //                return res*2;
        //            }
        //            if (thr != null) {
        //                return 1;
        //            }
        //            return 0;
        //        });

        /**
         * 3、线程串行化
         * thenRun thenAccept  thenApply 同步
         * thenRunAsync   thenAcceptAsync  thenApplyAsync 异步
         *
         *  1）、thenRun 不能获取到上一步的执行结果，无返回值
         *      .thenRunAsync(()->{
         *            System.out.printf("thenRunAsync==>%3s \n", "任务2启动了");
         *         },executor);
         *   2）、thenAccept 能接受上一步的结果，但是没有返回
         *      .thenAcceptAsync(res->{
         *            System.out.printf("任务2启动了,上一步的结果是==>%3s \n",res);
         *        },executor);
         *    3）、thenApply 能接受上一步的结果，还有返回值
         */
        //CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
        //    System.out.printf("当前线程==>%3s \n", Thread.currentThread().getName());
        //    int i = 10 / 4;
        //    System.out.printf("运行结果==>%3d \n", i);
        //    return i;
        //}, executor).thenApplyAsync(res -> {
        //    System.out.printf("任务2启动了,上一步的结果是==>%3s \n", res);
        //    return "hello  " + res;
        //}, executor);

        /**
         * 1、两个都完成
         */
        //CompletableFuture<Object> future01 = CompletableFuture.supplyAsync(() -> {
        //    System.out.printf("任务1线程==>%3s \n", Thread.currentThread().getId()+"");
        //    int i = 10 / 4;
        //    System.out.printf("任务1结束==>%3d \n", i);
        //    return i;
        //}, executor);
        //
        //CompletableFuture<Object> future02 = CompletableFuture.supplyAsync(() -> {
        //    System.out.printf("任务2线程==>%3s \n", Thread.currentThread().getId()+"");
        //
        //    try {
        //        TimeUnit.SECONDS.sleep(3);
        //    } catch (InterruptedException e) {
        //        e.printStackTrace();
        //    }
        //    System.out.println("任务2结束");
        //    return "hello";
        //}, executor);

        /**
         * 1、无前两个任务的返回，执行任务3，任务3无返回
         */
        //future01.runAfterBothAsync(future02,()->{
        //    System.out.println("任务3开始");
        //},executor);
        /**
         * 2、有前两个任务的返回，执行任务3，任务3无返回
         */
        //future01.thenAcceptBothAsync(future02,(f1,f2)->{
        //    System.out.printf("任务3开始,之前的结果==>%3s ==>%3s\n",f1,f2);
        //},executor);

        /**
         * 3、有前两个任务的返回，执行任务3，任务3有返回
         */
        //CompletableFuture<String> future03 = future01.thenCombineAsync(future02, (f1, f2) -> {
        //    System.out.printf("任务3开始,之前的结果==>%3s ==>%3s\n",f1,f2);
        //    return f1 +":"+ f2+"==>拼接";
        //}, executor);

        /**
         * 4、两个任务只要有一个任务完成，我们就执行任务3
         *  没有之前的两个任务的返回结果，自己也没有返回
         */
        //future01.runAfterEitherAsync(future02,()->{
        //    System.out.println("任务3开始");
        //},executor);
        /**
         * 5、两个任务只要有一个任务完成，我们就执行任务3
         *  感知前面两个任务中的返回结果（满足一个就可以），不返回结果，任务3也不返回结果
         */
        //future01.acceptEitherAsync(future02,res->{
        //    System.out.printf("任务3开始==>%3s \n", res);
        //}, executor);
        /**
         * 6、两个任务只要有一个任务完成，我们就执行任务3
         * 感知前面两个任务中的返回结果（满足一个就可以），返回结果，并返回任务3结果
         */
        //CompletableFuture<Object> future03 = future01.applyToEitherAsync(future02, res -> {
        //    System.out.printf("任务3开始==>%3s \n", res);
        //    return res.toString()+"-->哈哈";
        //}, executor);
        //System.out.printf("任务3返回==>%3s \n", future03.get());
        CompletableFuture<String> futureImg = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品图片信息");
            return "hello.jpg";
        }, executor);
        CompletableFuture<String> futureAttr = CompletableFuture.supplyAsync(() -> {
            System.out.println("查询商品属性信息");
            return "黑色+256G";
        }, executor);
        CompletableFuture<String> futureDesc = CompletableFuture.supplyAsync(() -> {
            try {
                TimeUnit.SECONDS.sleep(3);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("查询商品介绍信息");
            return "华为";
        }, executor);
        /**
         * 1、三个任务全部完成才可以，需要调用get（）方法阻塞
         */
        //CompletableFuture<Void> allOf = CompletableFuture.allOf(futureImg, futureAttr, futureDesc);
        /**
         * 2、三个任务只要有一个任务成功就返回
         */
        CompletableFuture<Object> anyOf = CompletableFuture.anyOf(futureImg, futureAttr, futureDesc);
        anyOf.get();//等待所有结果完成
        //System.out.printf("图片==>%3s 属性==>%3s 介绍==>%3s \n", futureImg.get(),futureAttr.get(),futureDesc.get());
        System.out.printf("anyOf获得的结果==>%3s \n",  anyOf.get());
        System.out.printf("CompletableFuture==>%3s \n", "main...end");
    }

    public void threadTest(String[] args) throws ExecutionException, InterruptedException {
        System.out.printf("==>%3s \n", "main...start");
        /**
         * 1)、继承Thrcad
         *         Thread01 thread01 = new Thread01();
         *         thread01.start();
         * 2) 、实现Runnablc接口
         *        Runnable01 runnable01 = new Runnable01();
         *         new Thread(runnable01).start();
         * 3)、实现callabla接口+ FutureTash(可以拿到返回结果，可以处理异常)*
         *    FutureTask<Integer> futureTask = new FutureTask<>(new Callable01());
         *         //Integer integer = futureTask.get();
         *         new Thread(futureTask).start();
         *         //阻塞等待  等待整个线程执行完成，获取返回结果
         *         Integer integer = futureTask.get();
         *          System.out.printf("Callable返回结果==>%3d \n",integer );
         * 4) 、线程池
         *  我们以后再业务代码里面，以上三种启动线程的方式都不用。【将所有的多线程异步任务都交给线程池执行】
         *    new Thread(()-> System.out.println("hello")).start();
         *
         *    1、创建
         *      1）、Executors
         *      2）、new ThreadPoolExecutor();
         *    Future:可以获取到异步结果
         *          七大参数
         *           1、corePoolSize：核心线程数【一直存在 除非allowCoreThreadTimeOut】;线程池，创建好以后就准备就绪的线程数量，就等待来接受异步任务去执行
         *           2、maximumPoolSize：【200】 最大线程量；控制资源
         *           3、keepAliveTime： 【非核心线程】存活时间，当前线程大于核心线程数，释放空闲线程（maximumPoolSize-corePoolSize），只要空闲线程大于指定的存活时间 keepAliveTime
         *           4、unit： 非核心线程的时间单位
         *           5、workQueue：阻塞队列 BlockingQueue<Runnable> workQueue 就会将目前多的任务放在队列里面。
         *           只要有线程空闲,就会去队列里面取出新的任务继续执行。
         *           6、threadFactory： 线程创建工厂
         *           7、handler： RejectedExecutionHandler 如果队列满了，按照我们指定的拒绝策略拒绝执行任务
         *
         *          工作顺序：
         *          运行流程:
         * 1、线程池创建,准备好core数量的核心线程，准备接受任务
         * 2、新的任务进来，用core准备好的空闲线程执行。
         * 1.1、core满了，就将再进来的任务放入阻塞队列中。空闲的core就会自己去阻塞队列获取任务执行
         * 1.2、阻塞队列满了，就直接开新线程执行，最大只能开到max指定的数量
         * 1.3、max满了就用RejectedExecutionHandLer拒绝任务
         * 1.4、max都执行完成，有很多空闲.在指定的时间keepALiveTime以后，释放max-corc这些线程
         * newLinkedBLockingDeque<>(100000):默认是Integer.MAX_VALUE。会导致内存不够，指定任务数量
         * 3、所有的线程创建都是由指定的 factory 创建的。
         *
         *    面试:
         * 一个线程池core 7 max 20 . queue: 50，100并发进来怎么分配的;
         * 先有7个能直接得到执行，接下来50个进入队列排队，在多开13个继续执行。现在70个被安排上了。剩下30个默认拒绝策略。
         *  如果不想抛弃还要执行 CallerRunsPolicy；以同步的方式执行
         *
         *    区别：
         *    1、2不能得到返回值，3、可以得到返回值
         *    1、2、3都不能控制资源
         *    4、可以控制资源 ，性能稳定*
         *
         */

        //当前系统中池只有一两个，每个异步任务，提交给线程池让他自己去执行就行
        ThreadPoolExecutor executor = new ThreadPoolExecutor(5,
                200,
                10,
                TimeUnit.SECONDS,
                new LinkedBlockingDeque<>(100000),
                Executors.defaultThreadFactory(),
                new ThreadPoolExecutor.AbortPolicy());

        //Executors.newCachedThreadPool()   core是0，所有都可以回收
        //Executors.newFixedThreadPool()  固定大小  core=max  都不可以回收
        //Executors.newScheduledThreadPool()  定时任务的线程池
        //Executors.newSingleThreadExecutor()  单线程的线程池，后台从队列中获取任务，单个执行


        executor.execute(() -> System.out.println(10 / 2));
        System.out.println(executor.submit(() -> 10 / 2).get());
        System.out.printf("==>%3s \n", "main...end");
    }

    public static class Thread01 extends Thread {
        @Override
        public void run() {
            System.out.printf("当前线程==>%3s \n", Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.printf("运行结果==>%3d \n", i);
        }
    }

    public static class Runnable01 implements Runnable {
        @Override
        public void run() {
            System.out.printf("当前线程==>%3s \n", Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.printf("运行结果==>%3d \n", i);
        }
    }

    public static class Callable01 implements Callable<Integer> {

        @Override
        public Integer call() {
            System.out.printf("当前线程==>%3s \n", Thread.currentThread().getName());
            int i = 10 / 2;
            System.out.printf("运行结果==>%3d \n", i);
            return i;
        }
    }
}
